๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ์ค๋ ๋ ์์ ํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ฅผ ์ํ ์๋ฐ์คํฌ๋ฆฝํธ Concurrent HashMap์ ์ดํด์ ๊ตฌํ์ ๋ํ ์ข ํฉ ๊ฐ์ด๋์ ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ Concurrent HashMap: ์ค๋ ๋ ์์ ํ ๋ฐ์ดํฐ ๊ตฌ์กฐ ๋ง์คํฐํ๊ธฐ
์๋ฐ์คํฌ๋ฆฝํธ์ ์ธ๊ณ, ํนํ Node.js์ ๊ฐ์ ์๋ฒ์ฌ์ด๋ ํ๊ฒฝ๊ณผ ์น ์์ปค๋ฅผ ํตํด ์น ๋ธ๋ผ์ฐ์ ๋ด์์๋ ๋์์ฑ ํ๋ก๊ทธ๋๋ฐ์ด ์ ์ ๋ ์ค์ํด์ง๊ณ ์์ต๋๋ค. ์ฌ๋ฌ ์ค๋ ๋๋ ๋น๋๊ธฐ ์์ ๊ฐ์ ๊ณต์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ฒ ์ฒ๋ฆฌํ๋ ๊ฒ์ ๊ฒฌ๊ณ ํ๊ณ ํ์ฅ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ๊ฐ์ฅ ์ค์ํฉ๋๋ค. ๋ฐ๋ก ์ด ์ง์ ์์ Concurrent HashMap์ด ์ค์ํ ์ญํ ์ ํฉ๋๋ค.
Concurrent HashMap์ด๋ ๋ฌด์์ธ๊ฐ?
Concurrent HashMap์ ๋ฐ์ดํฐ์ ๋ํ ์ค๋ ๋ ์์ ํ ์ ๊ทผ์ ์ ๊ณตํ๋ ํด์ ํ ์ด๋ธ ๊ตฌํ์ ๋๋ค. ๋ณธ์ง์ ์ผ๋ก ์ค๋ ๋์ ์์ ํ์ง ์์ ํ์ค ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์ฒด๋ `Map`๊ณผ๋ ๋ฌ๋ฆฌ, Concurrent HashMap์ ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋ฐ์ดํฐ๋ฅผ ์์์ํค๊ฑฐ๋ ๊ฒฝ์ ์กฐ๊ฑด(race condition)์ ์ ๋ฐํ์ง ์๊ณ ๋์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์ธ ์ ์๋๋ก ํ์ฉํฉ๋๋ค. ์ด๋ ๋ฝ(locking)์ด๋ ์์์ ์ฐ์ฐ(atomic operations)๊ณผ ๊ฐ์ ๋ด๋ถ ๋ฉ์ปค๋์ฆ์ ํตํด ๋ฌ์ฑ๋ฉ๋๋ค.
๊ฐ๋จํ ๋น์ ๋ฅผ ์๊ฐํด ๋ณด์ธ์: ๊ณต์ ํ์ดํธ๋ณด๋๊ฐ ์๋ค๊ณ ์์ํด ๋ด ์๋ค. ์ฌ๋ฌ ์ฌ๋์ด ์๋ฌด๋ฐ ์กฐ์ ์์ด ๋์์ ๊ธ์ ์ฐ๋ ค๊ณ ํ๋ฉด ๊ฒฐ๊ณผ๋ ํผ๋์ค๋ฌ์ด ๋์ฅํ์ด ๋ ๊ฒ์ ๋๋ค. Concurrent HashMap์ ์ฌ๋๋ค์ด ํ ๋ฒ์ ํ ๋ช ์ฉ(๋๋ ํต์ ๋ ๊ทธ๋ฃน์ผ๋ก) ๊ธ์ ์ธ ์ ์๋๋ก ์ธ์ฌํ๊ฒ ๊ด๋ฆฌ๋๋ ์์คํ ์ ๊ฐ์ถ ํ์ดํธ๋ณด๋์ฒ๋ผ ์๋ํ์ฌ ์ ๋ณด๊ฐ ์ผ๊ด๋๊ณ ์ ํํ๊ฒ ์ ์ง๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
Concurrent HashMap์ ์ฌ์ฉํ๋ ์ด์
Concurrent HashMap์ ์ฌ์ฉํ๋ ์ฃผ๋ ์ด์ ๋ ๋์์ฑ ํ๊ฒฝ์์ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํจ์ ๋๋ค. ์ฃผ์ ์ด์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ค๋ ๋ ์์ ์ฑ: ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ๋งต์ ์ ๊ทผํ๊ณ ์์ ํ ๋ ๋ฐ์ํ๋ ๊ฒฝ์ ์กฐ๊ฑด๊ณผ ๋ฐ์ดํฐ ์์์ ๋ฐฉ์งํฉ๋๋ค.
- ์ฑ๋ฅ ํฅ์: ๋์ ์ฝ๊ธฐ ์์ ์ ํ์ฉํ์ฌ ๋ฉํฐ์ค๋ ๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์๋นํ ์ฑ๋ฅ ํฅ์์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ์ผ๋ถ ๊ตฌํ์ ๋งต์ ๋ค๋ฅธ ๋ถ๋ถ์ ๋ํ ๋์ ์ฐ๊ธฐ๋ ํ์ฉํ ์ ์์ต๋๋ค.
- ํ์ฅ์ฑ: ์ฌ๋ฌ ์ฝ์ด์ ์ค๋ ๋๋ฅผ ํ์ฉํ์ฌ ์ฆ๊ฐํ๋ ์ํฌ๋ก๋๋ฅผ ์ฒ๋ฆฌํจ์ผ๋ก์จ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ ํจ๊ณผ์ ์ผ๋ก ํ์ฅ๋ ์ ์๋๋ก ํฉ๋๋ค.
- ๊ฐ๋ฐ ๋จ์ํ: ์ค๋ ๋ ๋๊ธฐํ๋ฅผ ์๋์ผ๋ก ๊ด๋ฆฌํ๋ ๋ณต์ก์ฑ์ ์ค์ฌ ์ฝ๋๋ฅผ ๋ ์ฝ๊ฒ ์์ฑํ๊ณ ์ ์ง ๊ด๋ฆฌํ ์ ์๋๋ก ํฉ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ์์์ ๋์์ฑ ๋ฌธ์
์๋ฐ์คํฌ๋ฆฝํธ์ ์ด๋ฒคํธ ๋ฃจํ ๋ชจ๋ธ์ ๋ณธ์ง์ ์ผ๋ก ๋จ์ผ ์ค๋ ๋์ ๋๋ค. ์ด๋ ๋ธ๋ผ์ฐ์ ์ ๋ฉ์ธ ์ค๋ ๋๋ ๋จ์ผ ํ๋ก์ธ์ค Node.js ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ ํต์ ์ธ ์ค๋ ๋ ๊ธฐ๋ฐ ๋์์ฑ์ ์ง์ ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค. ๊ทธ๋ฌ๋ ์๋ฐ์คํฌ๋ฆฝํธ๋ ๋ค์์ ํตํด ๋์์ฑ์ ๋ฌ์ฑํฉ๋๋ค:
- ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ: `async/await`, Promises, ์ฝ๋ฐฑ์ ์ฌ์ฉํ์ฌ ๋ ผ๋ธ๋กํน(non-blocking) ์์ ์ ์ฒ๋ฆฌํฉ๋๋ค.
- ์น ์์ปค: ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ฅผ ์คํํ ์ ์๋ ๋ณ๋์ ์ค๋ ๋๋ฅผ ์์ฑํฉ๋๋ค.
- Node.js ํด๋ฌ์คํฐ: ์ฌ๋ฌ CPU ์ฝ์ด๋ฅผ ํ์ฉํ๊ธฐ ์ํด Node.js ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ๋ฌ ์ธ์คํด์ค๋ฅผ ์คํํฉ๋๋ค.
์ด๋ฌํ ๋ฉ์ปค๋์ฆ์ ์ฌ์ฉํ๋๋ผ๋ ๋น๋๊ธฐ ์์ ์ด๋ ์ฌ๋ฌ ์ค๋ ๋ ๊ฐ์ ๊ณต์ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ ์ฌ์ ํ ์ด๋ ค์ด ๊ณผ์ ์ ๋๋ค. ์ ์ ํ ๋๊ธฐํ ์์ด๋ ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ์ ์ง๋ฉดํ ์ ์์ต๋๋ค:
- ๊ฒฝ์ ์ํ: ์์ ์ ๊ฒฐ๊ณผ๊ฐ ์ฌ๋ฌ ์ค๋ ๋๊ฐ ์คํ๋๋ ์์ธก ๋ถ๊ฐ๋ฅํ ์์์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ๋ ๋ฐ์ํฉ๋๋ค.
- ๋ฐ์ดํฐ ์์: ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ๋์ผํ ๋ฐ์ดํฐ๋ฅผ ์์ ํ์ฌ ์ผ๊ด์ฑ์ด ์๊ฑฐ๋ ์๋ชป๋ ๊ฒฐ๊ณผ๋ฅผ ์ด๋ํ ๋ ๋ฐ์ํฉ๋๋ค.
- ๊ต์ฐฉ ์ํ(Deadlocks): ๋ ์ด์์ ์ค๋ ๋๊ฐ ์๋ก๊ฐ ์์์ ํด์ ํ๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ฉฐ ๋ฌด๊ธฐํ์ผ๋ก ์ฐจ๋จ๋ ๋ ๋ฐ์ํฉ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ์์ Concurrent HashMap ๊ตฌํํ๊ธฐ
์๋ฐ์คํฌ๋ฆฝํธ์๋ ๋ด์ฅ๋ Concurrent HashMap์ด ์์ง๋ง, ๋ค์ํ ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ ๊ตฌํํ ์ ์์ต๋๋ค. ์ฌ๊ธฐ์๋ ๊ฐ๊ฐ์ ์ฅ๋จ์ ์ ๋น๊ตํ๋ฉฐ ๋ค์ํ ์ ๊ทผ ๋ฐฉ์์ ์ดํด๋ณด๊ฒ ์ต๋๋ค:
1. `Atomics`์ `SharedArrayBuffer` ์ฌ์ฉํ๊ธฐ (์น ์์ปค)
์ด ์ ๊ทผ ๋ฐฉ์์ ์น ์์ปค์์ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๋์์ฑ์ ์ํด ํน๋ณํ ์ค๊ณ๋ `Atomics`์ `SharedArrayBuffer`๋ฅผ ํ์ฉํฉ๋๋ค. `SharedArrayBuffer`๋ ์ฌ๋ฌ ์น ์์ปค๊ฐ ๋์ผํ ๋ฉ๋ชจ๋ฆฌ ์์น์ ์ ๊ทผํ ์ ์๊ฒ ํด์ฃผ๋ฉฐ, `Atomics`๋ ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํ ์์์ ์ฐ์ฐ์ ์ ๊ณตํฉ๋๋ค.
์์ :
```javascript // main.js (๋ฉ์ธ ์ค๋ ๋) const worker = new Worker('worker.js'); const buffer = new SharedArrayBuffer(1024); const map = new ConcurrentHashMap(buffer); worker.postMessage({ buffer }); map.set('key1', 123); map.get('key1'); // ๋ฉ์ธ ์ค๋ ๋์์ ์ ๊ทผ // worker.js (์น ์์ปค) importScripts('concurrent-hashmap.js'); // ๊ฐ์ ๊ตฌํ self.onmessage = (event) => { const buffer = event.data.buffer; const map = new ConcurrentHashMap(buffer); map.set('key2', 456); console.log('์์ปค๋ก๋ถํฐ์ ๊ฐ:', map.get('key2')); }; ``` ```javascript // concurrent-hashmap.js (๊ฐ๋ ์ ๊ตฌํ) class ConcurrentHashMap { constructor(buffer) { this.buffer = new Int32Array(buffer); this.mutex = new Int32Array(new SharedArrayBuffer(4)); // ๋ฎคํ ์ค ๋ฝ // ํด์ฑ, ์ถฉ๋ ํด๊ฒฐ ๋ฑ์ ์ํ ๊ตฌํ ์ธ๋ถ ์ ๋ณด } // ๊ฐ์ ์ค์ ํ๊ธฐ ์ํ ์์์ ์ฐ์ฐ ์ฌ์ฉ ์์ set(key, value) { // Atomics.wait/wake๋ฅผ ์ฌ์ฉํ์ฌ ๋ฎคํ ์ค ์ ๊ธ Atomics.wait(this.mutex, 0, 1); // ๋ฎคํ ์ค๊ฐ 0(์ ๊ธ ํด์ )์ด ๋ ๋๊น์ง ๋๊ธฐ Atomics.store(this.mutex, 0, 1); // ๋ฎคํ ์ค๋ฅผ 1(์ ๊ธ)๋ก ์ค์ // ... ํค์ ๊ฐ์ ๋ฐ๋ผ ๋ฒํผ์ ์ฐ๊ธฐ ... Atomics.store(this.mutex, 0, 0); // ๋ฎคํ ์ค ์ ๊ธ ํด์ Atomics.notify(this.mutex, 0, 1); // ๋๊ธฐ ์ค์ธ ์ค๋ ๋ ๊นจ์ฐ๊ธฐ } get(key) { // ์ ์ฌํ ์ ๊ธ ๋ฐ ์ฝ๊ธฐ ๋ก์ง return this.buffer[hash(key) % this.buffer.length]; // ๋จ์ํ๋จ } } // ๊ฐ๋จํ ํด์ ํจ์๋ฅผ ์ํ ํ๋ ์ด์คํ๋ function hash(key) { return key.charCodeAt(0); // ๋งค์ฐ ๊ธฐ๋ณธ์ ์ด๋ฏ๋ก ํ๋ก๋์ ํ๊ฒฝ์๋ ์ ํฉํ์ง ์์ } ```์ค๋ช :
- `SharedArrayBuffer`๊ฐ ์์ฑ๋์ด ๋ฉ์ธ ์ค๋ ๋์ ์น ์์ปค ๊ฐ์ ๊ณต์ ๋ฉ๋๋ค.
- `ConcurrentHashMap` ํด๋์ค(์ฌ๊ธฐ์๋ ๋ณด์ฌ์ฃผ์ง ์์ ์๋นํ ๊ตฌํ ์ธ๋ถ์ฌํญ์ด ํ์ํจ)๋ ๊ณต์ ๋ฒํผ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฉ์ธ ์ค๋ ๋์ ์น ์์ปค ์์ชฝ์์ ์ธ์คํด์คํ๋ฉ๋๋ค. ์ด ํด๋์ค๋ ๊ฐ์ ๊ตฌํ์ด๋ฉฐ ๊ธฐ๋ณธ ๋ก์ง์ ๊ตฌํํด์ผ ํฉ๋๋ค.
- ์์์ ์ฐ์ฐ(`Atomics.wait`, `Atomics.store`, `Atomics.notify`)์ ๊ณต์ ๋ฒํผ์ ๋ํ ์ ๊ทผ์ ๋๊ธฐํํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ด ๊ฐ๋จํ ์์ ๋ ๋ฎคํ ์ค(์ํธ ๋ฐฐ์ ) ๋ฝ์ ๊ตฌํํฉ๋๋ค.
- `set` ๋ฐ `get` ๋ฉ์๋๋ `SharedArrayBuffer` ๋ด์์ ์ค์ ํด์ฑ ๋ฐ ์ถฉ๋ ํด๊ฒฐ ๋ก์ง์ ๊ตฌํํด์ผ ํฉ๋๋ค.
์ฅ์ :
- ๊ณต์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํตํ ์ง์ ํ ๋์์ฑ.
- ๋๊ธฐํ์ ๋ํ ์ธ๋ฐํ ์ ์ด.
- ์ฝ๊ธฐ ์ค์ฌ์ ์ํฌ๋ก๋์์ ์ ์ฌ์ ์ผ๋ก ๋์ ์ฑ๋ฅ.
๋จ์ :
- ๋ณต์กํ ๊ตฌํ.
- ๊ต์ฐฉ ์ํ์ ๊ฒฝ์ ์กฐ๊ฑด์ ํผํ๊ธฐ ์ํด ๋ฉ๋ชจ๋ฆฌ์ ๋๊ธฐํ์ ๋ํ ์ธ์ฌํ ๊ด๋ฆฌ๊ฐ ํ์ํฉ๋๋ค.
- ์ด์ ๋ฒ์ ๋ธ๋ผ์ฐ์ ์์๋ ์ง์์ด ์ ํ๋ฉ๋๋ค.
- `SharedArrayBuffer`๋ ๋ณด์์์ ์ด์ ๋ก ํน์ HTTP ํค๋(COOP/COEP)๊ฐ ํ์ํฉ๋๋ค.
2. ๋ฉ์์ง ์ ๋ฌ ์ฌ์ฉํ๊ธฐ (์น ์์ปค ๋ฐ Node.js ํด๋ฌ์คํฐ)
์ด ์ ๊ทผ ๋ฐฉ์์ ์ค๋ ๋๋ ํ๋ก์ธ์ค ๊ฐ์ ๋ฉ์์ง ์ ๋ฌ์ ์์กดํ์ฌ ๋งต์ ๋ํ ์ ๊ทผ์ ๋๊ธฐํํฉ๋๋ค. ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ง์ ๊ณต์ ํ๋ ๋์ , ์ค๋ ๋๋ ์๋ก ๋ฉ์์ง๋ฅผ ๋ณด๋ด ํต์ ํฉ๋๋ค.
์์ (์น ์์ปค):
```javascript // main.js const worker = new Worker('worker.js'); const map = {}; // ๋ฉ์ธ ์ค๋ ๋์ ์ค์ ์ง์ค์ ๋งต function set(key, value) { return new Promise((resolve, reject) => { worker.postMessage({ type: 'set', key, value }); worker.onmessage = (event) => { if (event.data.type === 'setResponse') { resolve(event.data.success); } }; worker.onerror = (error) => { reject(error); }; }); } function get(key) { return new Promise((resolve, reject) => { worker.postMessage({ type: 'get', key }); worker.onmessage = (event) => { if (event.data.type === 'getResponse') { resolve(event.data.value); } }; }); } // ์ฌ์ฉ ์์ set('key1', 123).then(success => console.log('์ค์ ์ฑ๊ณต:', success)); get('key1').then(value => console.log('๊ฐ:', value)); // worker.js self.onmessage = (event) => { const data = event.data; switch (data.type) { case 'set': map[data.key] = data.value; self.postMessage({ type: 'setResponse', success: true }); break; case 'get': self.postMessage({ type: 'getResponse', value: map[data.key] }); break; } }; let map = {}; ```์ค๋ช :
- ๋ฉ์ธ ์ค๋ ๋๊ฐ ์ค์ `map` ๊ฐ์ฒด๋ฅผ ์ ์ง ๊ด๋ฆฌํฉ๋๋ค.
- ์น ์์ปค๊ฐ ๋งต์ ์ ๊ทผํ๊ณ ์ถ์ ๋, ์ํ๋ ์์ (์: 'set', 'get')๊ณผ ํด๋น ๋ฐ์ดํฐ(ํค, ๊ฐ)๋ฅผ ๋ด์ ๋ฉ์์ง๋ฅผ ๋ฉ์ธ ์ค๋ ๋๋ก ๋ณด๋ ๋๋ค.
- ๋ฉ์ธ ์ค๋ ๋๋ ๋ฉ์์ง๋ฅผ ์์ ํ๊ณ , ๋งต์ ๋ํ ์์ ์ ์ํํ ๋ค์, ์๋ต์ ๋ค์ ์น ์์ปค๋ก ๋ณด๋ ๋๋ค.
์ฅ์ :
- ๊ตฌํ์ด ๋น๊ต์ ๊ฐ๋จํฉ๋๋ค.
- ๊ณต์ ๋ฉ๋ชจ๋ฆฌ์ ์์์ ์ฐ์ฐ์ ๋ณต์ก์ฑ์ ํผํ ์ ์์ต๋๋ค.
- ๊ณต์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์๊ฑฐ๋ ์ค์ฉ์ ์ด์ง ์์ ํ๊ฒฝ์์ ์ ์๋ํฉ๋๋ค.
๋จ์ :
- ๋ฉ์์ง ์ ๋ฌ๋ก ์ธํ ์ค๋ฒํค๋๊ฐ ๋์ต๋๋ค.
- ๋ฉ์์ง์ ์ง๋ ฌํ ๋ฐ ์ญ์ง๋ ฌํ๊ฐ ์ฑ๋ฅ์ ์ํฅ์ ์ค ์ ์์ต๋๋ค.
- ๋ฉ์ธ ์ค๋ ๋์ ๋ถํ๊ฐ ๋ง์ผ๋ฉด ์ง์ฐ์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
- ๋ฉ์ธ ์ค๋ ๋๊ฐ ๋ณ๋ชฉ ํ์์ ์์ธ์ด ๋ฉ๋๋ค.
์์ (Node.js ํด๋ฌ์คํฐ):
```javascript // app.js const cluster = require('cluster'); const http = require('http'); const numCPUs = require('os').cpus().length; let map = {}; // ์ค์ ์ง์ค์ ๋งต (Redis/๊ธฐํ๋ฅผ ์ฌ์ฉํ์ฌ ์์ปค ๊ฐ ๊ณต์ ) if (cluster.isMaster) { console.log(`๋ง์คํฐ ${process.pid}๊ฐ ์คํ ์ค์ ๋๋ค`); // ์์ปค๋ฅผ ํฌํฌํฉ๋๋ค. for (let i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', (worker, code, signal) => { console.log(`์์ปค ${worker.process.pid}๊ฐ ์ข ๋ฃ๋์์ต๋๋ค`); }); } else { // ์์ปค๋ TCP ์ฐ๊ฒฐ์ ๊ณต์ ํ ์ ์์ต๋๋ค // ์ด ๊ฒฝ์ฐ HTTP ์๋ฒ์ ๋๋ค http.createServer((req, res) => { // ์์ฒญ์ ์ฒ๋ฆฌํ๊ณ ๊ณต์ ๋งต์ ์ ๊ทผ/์ ๋ฐ์ดํธ // ๋งต ์ ๊ทผ ์๋ฎฌ๋ ์ด์ const key = req.url.substring(1); // URL์ด ํค๋ผ๊ณ ๊ฐ์ if (req.method === 'GET') { const value = map[key]; // ๊ณต์ ๋งต์ ์ ๊ทผ res.writeHead(200); res.end(`${key}์ ๊ฐ: ${value}`); } else if (req.method === 'POST') { // ์์ : ๊ฐ ์ค์ let body = ''; req.on('data', chunk => { body += chunk.toString(); // ๋ฒํผ๋ฅผ ๋ฌธ์์ด๋ก ๋ณํ }); req.on('end', () => { map[key] = body; // ๋งต ์ ๋ฐ์ดํธ (์ค๋ ๋ ์์ ํ์ง ์์) res.writeHead(200); res.end(`${key}๋ฅผ ${body}(์ผ)๋ก ์ค์ `); }); } }).listen(8000); console.log(`์์ปค ${process.pid}๊ฐ ์์๋์์ต๋๋ค`); } ```์ค์ ์ฐธ๊ณ ์ฌํญ: ์ด Node.js ํด๋ฌ์คํฐ ์์ ์์ `map` ๋ณ์๋ ๊ฐ ์์ปค ํ๋ก์ธ์ค ๋ด์์ ๋ก์ปฌ๋ก ์ ์ธ๋ฉ๋๋ค. ๋ฐ๋ผ์ ํ ์์ปค์์ `map`์ ์์ ํด๋ ๋ค๋ฅธ ์์ปค์๋ ๋ฐ์๋์ง ์์ต๋๋ค. ํด๋ฌ์คํฐ ํ๊ฒฝ์์ ๋ฐ์ดํฐ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ณต์ ํ๋ ค๋ฉด Redis, Memcached ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ฐ์ ์ธ๋ถ ๋ฐ์ดํฐ ์ ์ฅ์๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
์ด ๋ชจ๋ธ์ ์ฃผ์ ์ด์ ์ ์ฌ๋ฌ ์ฝ์ด์ ์ํฌ๋ก๋๋ฅผ ๋ถ์ฐ์ํค๋ ๊ฒ์ ๋๋ค. ์ง์ ํ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ ๊ทผ์ ๋๊ธฐํํ๋ ค๋ฉด ํ๋ก์ธ์ค ๊ฐ ํต์ (inter-process communication)์ ์ฌ์ฉํด์ผ ํ๋ฉฐ, ์ด๋ ์ผ๊ด๋ Concurrent HashMap์ ์ ์งํ๋ ๊ฒ์ ๋ณต์กํ๊ฒ ๋ง๋ญ๋๋ค.
3. ๋๊ธฐํ๋ฅผ ์ํ ์ ์ฉ ์ค๋ ๋๋ฅผ ๊ฐ์ง ๋จ์ผ ํ๋ก์ธ์ค ์ฌ์ฉํ๊ธฐ (Node.js)
์ด ํจํด์ ๋ ์ผ๋ฐ์ ์ด์ง๋ง ํน์ ์๋๋ฆฌ์ค์์ ์ ์ฉํ๋ฉฐ, ๊ณต์ ๋ฐ์ดํฐ์ ๋ํ ์ ๊ทผ์ ์ ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ์ ์ฉ ์ค๋ ๋(Node.js์ `worker_threads`์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ)๋ฅผ ํฌํจํฉ๋๋ค. ๋ค๋ฅธ ๋ชจ๋ ์ค๋ ๋๋ ๋งต์ ์ฝ๊ฑฐ๋ ์ฐ๊ธฐ ์ํด ์ด ์ ์ฉ ์ค๋ ๋์ ํต์ ํด์ผ ํฉ๋๋ค.
์์ (Node.js):
```javascript // main.js const { Worker } = require('worker_threads'); const worker = new Worker('./map-worker.js'); function set(key, value) { return new Promise((resolve, reject) => { worker.postMessage({ type: 'set', key, value }); worker.on('message', (message) => { if (message.type === 'setResponse') { resolve(message.success); } }); worker.on('error', reject); }); } function get(key) { return new Promise((resolve, reject) => { worker.postMessage({ type: 'get', key }); worker.on('message', (message) => { if (message.type === 'getResponse') { resolve(message.value); } }); worker.on('error', reject); }); } // ์ฌ์ฉ ์์ set('key1', 123).then(success => console.log('์ค์ ์ฑ๊ณต:', success)); get('key1').then(value => console.log('๊ฐ:', value)); // map-worker.js const { parentPort } = require('worker_threads'); let map = {}; parentPort.on('message', (message) => { switch (message.type) { case 'set': map[message.key] = message.value; parentPort.postMessage({ type: 'setResponse', success: true }); break; case 'get': parentPort.postMessage({ type: 'getResponse', value: map[message.key] }); break; } }); ```์ค๋ช :
- `main.js`๋ `map-worker.js`๋ฅผ ์คํํ๋ `Worker`๋ฅผ ์์ฑํฉ๋๋ค.
- `map-worker.js`๋ `map` ๊ฐ์ฒด๋ฅผ ์์ ํ๊ณ ๊ด๋ฆฌํ๋ ์ ์ฉ ์ค๋ ๋์ ๋๋ค.
- `map`์ ๋ํ ๋ชจ๋ ์ ๊ทผ์ `map-worker.js` ์ค๋ ๋์ ์ฃผ๊ณ ๋ฐ๋ ๋ฉ์์ง๋ฅผ ํตํด ์ด๋ฃจ์ด์ง๋๋ค.
์ฅ์ :
- ๋จ ํ๋์ ์ค๋ ๋๋ง ๋งต๊ณผ ์ง์ ์ํธ ์์ฉํ๋ฏ๋ก ๋๊ธฐํ ๋ก์ง์ด ๋จ์ํ๋ฉ๋๋ค.
- ๊ฒฝ์ ์กฐ๊ฑด ๋ฐ ๋ฐ์ดํฐ ์์ ์ํ์ ์ค์ ๋๋ค.
๋จ์ :
- ์ ์ฉ ์ค๋ ๋์ ๊ณผ๋ถํ๊ฐ ๊ฑธ๋ฆฌ๋ฉด ๋ณ๋ชฉ ํ์์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
- ๋ฉ์์ง ์ ๋ฌ ์ค๋ฒํค๋๊ฐ ์ฑ๋ฅ์ ์ํฅ์ ์ค ์ ์์ต๋๋ค.
4. ๋ด์ฅ ๋์์ฑ ์ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉํ๊ธฐ (์ฌ์ฉ ๊ฐ๋ฅํ ๊ฒฝ์ฐ)
ํ์ฌ ์ฃผ๋ฅ ์๋ฐ์คํฌ๋ฆฝํธ์์ ๋๋ฆฌ ์ฌ์ฉ๋๋ ํจํด์ ์๋์ง๋ง, ์์์ ์ค๋ช ํ ์ ๊ทผ ๋ฐฉ์์ ํ์ฉํ์ฌ ๋ ๊ฒฌ๊ณ ํ Concurrent HashMap ๊ตฌํ์ ์ ๊ณตํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๊ฐ๋ฐ๋ ์ ์๊ฑฐ๋ (๋๋ ์ด๋ฏธ ์ ๋ฌธ ๋ถ์ผ์ ์กด์ฌํ ์ ์์) ์ฃผ๋ชฉํ ๊ฐ์น๊ฐ ์์ต๋๋ค. ํ๋ก๋์ ํ๊ฒฝ์์ ์ฌ์ฉํ๊ธฐ ์ ์ ํญ์ ์ด๋ฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฑ๋ฅ, ๋ณด์ ๋ฐ ์ ์ง ๊ด๋ฆฌ๋ฅผ ์ ์คํ๊ฒ ํ๊ฐํด์ผ ํฉ๋๋ค.
์ฌ๋ฐ๋ฅธ ์ ๊ทผ ๋ฐฉ์ ์ ํํ๊ธฐ
์๋ฐ์คํฌ๋ฆฝํธ์์ Concurrent HashMap์ ๊ตฌํํ๋ ์ต์์ ์ ๊ทผ ๋ฐฉ์์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํน์ ์๊ตฌ์ฌํญ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ค. ๋ค์ ์์๋ฅผ ๊ณ ๋ คํ์ญ์์ค:
- ํ๊ฒฝ: ์น ์์ปค๊ฐ ์๋ ๋ธ๋ผ์ฐ์ ์์ ์์ ํ๊ณ ์์ต๋๊น, ์๋๋ฉด Node.js ํ๊ฒฝ์์ ์์ ํ๊ณ ์์ต๋๊น?
- ๋์์ฑ ์์ค: ์ผ๋ง๋ ๋ง์ ์ค๋ ๋๋ ๋น๋๊ธฐ ์์ ์ด ๋์์ ๋งต์ ์ ๊ทผํ ๊ฒ์ ๋๊น?
- ์ฑ๋ฅ ์๊ตฌ์ฌํญ: ์ฝ๊ธฐ ๋ฐ ์ฐ๊ธฐ ์์ ์ ๋ํ ์ฑ๋ฅ ๊ธฐ๋์น๋ ๋ฌด์์ ๋๊น?
- ๋ณต์ก์ฑ: ์๋ฃจ์ ์ ๊ตฌํํ๊ณ ์ ์ง ๊ด๋ฆฌํ๋ ๋ฐ ์ผ๋ง๋ ๋ง์ ๋ ธ๋ ฅ์ ๊ธฐ์ธ์ผ ์ํฅ์ด ์์ต๋๊น?
๋ค์์ ๊ฐ๋จํ ๊ฐ์ด๋์ ๋๋ค:
- `Atomics`์ `SharedArrayBuffer`: ์น ์์ปค ํ๊ฒฝ์์ ๊ณ ์ฑ๋ฅ, ์ธ๋ฐํ ์ ์ด์ ์ด์์ ์ด์ง๋ง ์๋นํ ๊ตฌํ ๋ ธ๋ ฅ๊ณผ ์ ์คํ ๊ด๋ฆฌ๊ฐ ํ์ํฉ๋๋ค.
- ๋ฉ์์ง ์ ๋ฌ: ๊ณต์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์๊ฑฐ๋ ์ค์ฉ์ ์ด์ง ์์ ๊ฐ๋จํ ์๋๋ฆฌ์ค์ ์ ํฉํ์ง๋ง ๋ฉ์์ง ์ ๋ฌ ์ค๋ฒํค๋๊ฐ ์ฑ๋ฅ์ ์ํฅ์ ์ค ์ ์์ต๋๋ค. ๋จ์ผ ์ค๋ ๋๊ฐ ์ค์ ์กฐ์ ์ ์ญํ ์ ํ ์ ์๋ ์ํฉ์ ๊ฐ์ฅ ์ข์ต๋๋ค.
- ์ ์ฉ ์ค๋ ๋: ๊ณต์ ์ํ ๊ด๋ฆฌ๋ฅผ ๋จ์ผ ์ค๋ ๋ ๋ด์ ์บก์ํํ์ฌ ๋์์ฑ ๋ณต์ก์ฑ์ ์ค์ด๋ ๋ฐ ์ ์ฉํฉ๋๋ค.
- ์ธ๋ถ ๋ฐ์ดํฐ ์ ์ฅ์ (Redis ๋ฑ): ์ฌ๋ฌ Node.js ํด๋ฌ์คํฐ ์์ปค ๊ฐ์ ์ผ๊ด๋ ๊ณต์ ๋งต์ ์ ์ง ๊ด๋ฆฌํ๋ ๋ฐ ํ์ํฉ๋๋ค.
Concurrent HashMap ์ฌ์ฉ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
์ ํํ ๊ตฌํ ์ ๊ทผ ๋ฐฉ์์ ๊ด๊ณ์์ด Concurrent HashMap์ ์ ํํ๊ณ ํจ์จ์ ์ธ ์ฌ์ฉ์ ๋ณด์ฅํ๊ธฐ ์ํด ๋ค์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด์ญ์์ค:
- ๋ฝ ๊ฒฝํฉ ์ต์ํ: ์ค๋ ๋๊ฐ ๋ฝ์ ๋ณด์ ํ๋ ์๊ฐ์ ์ต์ํํ์ฌ ๋ ํฐ ๋์์ฑ์ ํ์ฉํ๋๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค๊ณํ์ญ์์ค.
- ์์์ ์ฐ์ฐ ํ๋ช ํ๊ฒ ์ฌ์ฉํ๊ธฐ: ์์์ ์ฐ์ฐ์ ๋น์์์ ์ฐ์ฐ๋ณด๋ค ๋น์ฉ์ด ๋ง์ด ๋ค ์ ์์ผ๋ฏ๋ก ํ์ํ ๋๋ง ์ฌ์ฉํ์ญ์์ค.
- ๊ต์ฐฉ ์ํ ํผํ๊ธฐ: ์ค๋ ๋๊ฐ ์ผ๊ด๋ ์์๋ก ๋ฝ์ ํ๋ํ๋๋ก ํ์ฌ ๊ต์ฐฉ ์ํ๋ฅผ ํผํ๋๋ก ์ฃผ์ํ์ญ์์ค.
- ์ฒ ์ ํ๊ฒ ํ ์คํธํ๊ธฐ: ๊ฒฝ์ ์กฐ๊ฑด์ด๋ ๋ฐ์ดํฐ ์์ ๋ฌธ์ ๋ฅผ ์๋ณํ๊ณ ์์ ํ๊ธฐ ์ํด ๋์์ฑ ํ๊ฒฝ์์ ์ฝ๋๋ฅผ ์ฒ ์ ํ ํ ์คํธํ์ญ์์ค. ๋์์ฑ์ ์๋ฎฌ๋ ์ด์ ํ ์ ์๋ ํ ์คํธ ํ๋ ์์ํฌ ์ฌ์ฉ์ ๊ณ ๋ คํ์ญ์์ค.
- ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง: Concurrent HashMap์ ์ฑ๋ฅ์ ๋ชจ๋ํฐ๋งํ์ฌ ๋ณ๋ชฉ ํ์์ ์๋ณํ๊ณ ๊ทธ์ ๋ฐ๋ผ ์ต์ ํํ์ญ์์ค. ํ๋กํ์ผ๋ง ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋๊ธฐํ ๋ฉ์ปค๋์ฆ์ด ์ด๋ป๊ฒ ์ํ๋๋์ง ์ดํดํ์ญ์์ค.
๊ฒฐ๋ก
Concurrent HashMap์ ์๋ฐ์คํฌ๋ฆฝํธ์์ ์ค๋ ๋์ ์์ ํ๊ณ ํ์ฅ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๊ธฐ ์ํ ๊ท์คํ ๋๊ตฌ์ ๋๋ค. ๋ค์ํ ๊ตฌํ ์ ๊ทผ ๋ฐฉ์์ ์ดํดํ๊ณ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด๋ฉด ๋์์ฑ ํ๊ฒฝ์์ ๊ณต์ ๋ฐ์ดํฐ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ๊ณ ๊ฒฌ๊ณ ํ๋ฉฐ ์ฑ๋ฅ์ด ๋ฐ์ด๋ ์ํํธ์จ์ด๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ์น ์์ปค์ Node.js๋ฅผ ํตํด ๊ณ์ ๋ฐ์ ํ๊ณ ๋์์ฑ์ ์์ฉํจ์ ๋ฐ๋ผ ์ค๋ ๋ ์์ ํ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ๋ง์คํฐํ๋ ๊ฒ์ ์ค์์ฑ์ ๋์ฑ ์ปค์ง ๊ฒ์ ๋๋ค.
์ ํ๋ฆฌ์ผ์ด์ ์ ํน์ ์๊ตฌ์ฌํญ์ ์ ์คํ๊ฒ ๊ณ ๋ คํ๊ณ ์ฑ๋ฅ, ๋ณต์ก์ฑ ๋ฐ ์ ์ง ๊ด๋ฆฌ ๊ฐ๋ฅ์ฑ ๊ฐ์ ๊ท ํ์ ๊ฐ์ฅ ์ ๋ง์ถ๋ ์ ๊ทผ ๋ฐฉ์์ ์ ํํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค. ์ฆ๊ฑฐ์ด ์ฝ๋ฉ ๋์ธ์!